package com.zyx.juel.holder;

import com.zyx.juel.entity.MyBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;


/**
 * <p>Spring的ApplicationContext的持有者，可以用静态方法的方式获取spring容器中的bean</p>
 *
 * @author Yaxi.Zhang
 * @since 2022/9/14 17:24
 */
@Slf4j
@Component
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("------------>Spring上下文正在初始化,APPLICATION NAME:" + applicationContext.getDisplayName() + "<-----------------------");
        SpringContextHolder.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        if (SpringContextHolder.applicationContext == null) {
            throw new RuntimeException("ApplicationContext属性为NULL,请检查是否注入了SpringContextHolder!");
        }
        return applicationContext;
    }

    /**
     * 在 Spring 中，什么对象最常见？当然是 bean, 那么我们可以直接通过 SpEL 访问 bean 的属性、调用方法么？
     * <p>
     * 要访问 bean 对象，所以我们的EvaluationContext中需要包含 bean 对象才行
     * <p>
     * 借助BeanResolver来实现，如context.setBeanResolver(new BeanFactoryResolver(applicationContext));
     * 其次访问 bean 的前缀修饰为@符号
     * 为了演示这种场景，首先创建一个普通的 Bean 对象
     */
    public static void bean() {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));

        // 获取bean对象
        MyBean myBean = parser.parseExpression("@myBean").getValue(context, MyBean.class);
        System.out.println("bean: " + myBean);

        // 访问bean方法
        String ans = parser.parseExpression("@myBean.hello('一灰灰blog')").getValue(context, String.class);
        System.out.println("bean method return: " + ans);
    }

}